﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dokan;
using System.Threading;
using System.IO;

namespace AzureDriveCore
{
	public class VirtualDriveService
	{
		private static Dictionary<string, VirtualDriveService> _drives = new Dictionary<string, VirtualDriveService>();

		private VirtualDriveService()
		{
		}

		public static VirtualDriveService Start(string driveLetter, string volumeLabel, string azureStorageConnectionString)
		{
			Uri driveUri;

			if (Uri.TryCreate(driveLetter + @":\", UriKind.Absolute, out driveUri) == false)
			{
				throw new ArgumentException("The driveLetter suplied is not valid.");
			}

			driveLetter = driveUri.LocalPath.ToUpper();

			VirtualDriveService result = null;

			lock (_drives)
			{
				if (_drives.ContainsKey(driveLetter))
				{
					throw new ArgumentException("The driveLetter suplied is already in use.");
				}

				result = new VirtualDriveService();

				_drives.Add(driveLetter, result);
			}

			result.DriveLetter = driveLetter;
			result.VolumeLabel = volumeLabel;
			result.AzureStorageConnectionString = azureStorageConnectionString;

			result.Initialize();

			return result;
		}

		public static bool Stop(string driveLetter)
		{
			Uri driveUri;

			if (Uri.TryCreate(driveLetter + @":\", UriKind.Absolute, out driveUri) == false)
			{
				throw new ArgumentException("The driveLetter suplied is not valid.");
			}

			driveLetter = driveUri.LocalPath.ToUpper();

			lock (_drives)
			{
				if (_drives.ContainsKey(driveLetter))
				{
					var result = DokanNet.DokanUnmount(driveLetter[0]);

					switch (result)
					{
						case 0:
						case 1:
							{
								_drives.Remove(driveLetter);

								return true;
							}
					}
				}
				else
				{
					return true;
				}
			}

			return false;
		}

		#region Fields

		private Thread _hostThread;

		#endregion Fields

		#region Properties

		public string DriveLetter { get; private set; }

		public string VolumeLabel { get; private set; }

		public string AzureStorageConnectionString { get; private set; }

		#endregion Properties

		private void Initialize()
		{
			var gate = new ManualResetEvent(false);

			this._hostThread = new Thread(new ThreadStart(delegate
			{
				var opt = new DokanOptions
				{
					MountPoint = this.DriveLetter,
					DebugMode = false,
					UseStdErr = false,
					VolumeLabel = this.VolumeLabel,
				};

				// Blocks the current thread, unless there was an error.
				int status = DokanNet.DokanMain(opt, new AzureFileManager(this.AzureStorageConnectionString));

				gate.Set();

				switch (status)
				{
					case DokanNet.DOKAN_DRIVE_LETTER_ERROR:
						Console.WriteLine("Drvie letter error");
						break;
					case DokanNet.DOKAN_DRIVER_INSTALL_ERROR:
						Console.WriteLine("Driver install error");
						break;
					case DokanNet.DOKAN_MOUNT_ERROR:
						Console.WriteLine("Mount error");
						break;
					case DokanNet.DOKAN_START_ERROR:
						Console.WriteLine("Start error");
						break;
					case DokanNet.DOKAN_ERROR:
						Console.WriteLine("Unknown error");
						break;
					case DokanNet.DOKAN_SUCCESS:
						Console.WriteLine("Success");
						break;
					default:
						Console.WriteLine("Unknown status: {0}", status);
						break;
				}
			}))
			{
				IsBackground = true,
			};

			this._hostThread.Start();

			do
			{
				if (Environment.GetLogicalDrives().Any(item => item == this.DriveLetter))
				{
					Console.WriteLine("Directory created!!!");

					break;
				}
			}
			while (gate.WaitOne(100) == false);
		}
	}
}
